コメントの作成と表示
====================

このセクションでは、コメントの表示と作成の機能を実装します。

ユーザのインタラクティブ性を向上するために、入力欄への入力が確定するたびにエラー表示をします。いわゆるクライアントサイドの入力検証(client-side input validation)です。これを Yii で行う方法を説明します。シームレスそして極めて簡単にできます。この機能は Yii バージョン 1.1.1 以降でサポートされていることに注意して下さい。


コメントの表示
--------------

コメントの表示・作成に個別のページを使う代わりに、記事の詳細ページ (`PostController` の `view` アクションで生成される) を使います。記事内容の表示の下に、まず、その記事に属するコメントをリスト表示し、次にコメントの投稿フォームを表示します。

記事の詳細ページにコメントを表示するため、ビュースクリプト `/wwwroot/blog/protected/views/post/view.php` を以下のように修正します。

~~~
[php]
... ここに記事の表示 ...

<div id="comments">
	<?php if($model->commentCount>=1): ?>
		<h3>
			<?php echo $model->commentCount . '個のコメント'; ?>
		</h3>

		<?php $this->renderPartial('_comments',array(
			'post'=>$model,
			'comments'=>$model->comments,
		)); ?>
	<?php endif; ?>
</div>
~~~

上の例では、現在の記事に属するコメント一覧を表示するために、`_comments` という部分的ビューを指定して `renderPartial()` を呼んでいます。ビューで `$model->comments` という式を使って記事に属するコメントを取得していることに注目して下さい。この式が使える理由は `Post` クラスで `comments` リレーションを宣言しているからです。この式が評価されると、暗黙的にデータベースの JOIN クエリーが発行され、適切なコメントが返されます。この機能は [遅延リレーショナルクエリ](http://www.yiiframework.com/doc/guide/ja/database.arr) として知られています。

部分的ビュー (partial view) の `_comments` はあまり興味深いものではありません。コメントを一つ一つ取り扱い、コメントの詳細を表示します。興味のある方は `/wwwroot/yii/demos/blog/protected/views/post/_comments.php` を参照してください。

コメントの作成
--------------

コメントの作成を扱うために、`PostController` の `actionView()` メソッドを以下のように修正します。

~~~
[php]
public function actionView()
{
	$post=$this->loadModel();
	$comment=$this->newComment($post);

	$this->render('view',array(
		'model'=>$post,
		'comment'=>$comment,
	));
}

protected function newComment($post)
{
	$comment=new Comment;
	if(isset($_POST['Comment']))
	{
		$comment->attributes=$_POST['Comment'];
		if($post->addComment($comment))
		{
			if($comment->status==Comment::STATUS_PENDING)
				Yii::app()->user->setFlash('commentSubmitted','コメント、有難うございます。コメントは承認後に投稿されます。');
			$this->refresh();
		}
	}
	return $comment;
}
~~~

それから `Post` モデルクラスを修正して、`addComment()` メソッドを以下のように追加します。

~~~
[php]
public function addComment($comment)
{
	if(Yii::app()->params['commentNeedApproval'])
		$comment->status=Comment::STATUS_PENDING;
	else
		$comment->status=Comment::STATUS_APPROVED;
	$comment->post_id=$this->id;
	return $comment->save();
}
~~~

上記コードでは、`view` を表示する前に `newComment()` メソッドを呼んでいます。`newComment()` メソッドでは、`Comment` インスタンスを生成し、コメントフォームが送信されたかどうかをチェックします。もし送信されていた場合、`$post->addComment($comment)` を呼んで記事にコメントを追加しようとします。問題なく進んだら記事の詳細ページをリフレッシュします。再表示されたページには、コメント承認制でなければ、新しく投稿されたコメントが表示されます。表示前にコメントの承認が必要な場合は、フラッシュメッセージを使って、承認が必要であることをユーザに示します。フラッシュメッセージは大抵、エンドユーザに確認メッセージを見せるものです。ユーザがブラウザの再読み込みボタンをクリックしたら、メッセージは消えます。

さらに `/wwwroot/blog/protected/views/post/view.php` を修正します。

~~~
[php]
......
<div id="comments">
	......
	<h3>コメントする</h3>

	<?php if(Yii::app()->user->hasFlash('commentSubmitted')): ?>
		<div class="flash-success">
			<?php echo Yii::app()->user->getFlash('commentSubmitted'); ?>
		</div>
	<?php else: ?>
		<?php $this->renderPartial('/comment/_form',array(
			'model'=>$comment,
		)); ?>
	<?php endif; ?>

</div><!-- comments -->
~~~

上記コードでは、フラッシュメッセージがあれば、そのメッセージを表示します。もし無ければ、部分的ビュー `/wwwroot/blog/protected/views/comment/_form.php` を使ってコメント入力フォームを表示します。


AJAX ベースの検証
----------------------------------

ユーザエクスペリエンスを向上させるために、AJAX ベースのフォームフィールド検証を使うことが出来ます。AJAX ベースの検証によって、ユーザはフォーム項目に入力をするたびに検証のフィードバックを得ることが出来ます。すなわち、フォーム全体をサーバに送信する前に、検証のフィードバックが得られます。コメントの入力フォームに AJAX ベースの検証をサポートするために、コメントフォームのビュー `/wwwroot/blog/protected/views/comment/_form.php` と `newComment()` メソッドの両方に小さな変更を加える必要があります。

`_form.php` では、[CActiveForm] ウィジェットを作成するときに、[CActiveForm::enableAjaxValidation] を true に設定します。

~~~
[php]
<div class="form">

<?php $form=$this->beginWidget('CActiveForm', array(
	'id'=>'comment-form',
	'enableAjaxValidation'=>true,
)); ?>
......
<?php $this->endWidget(); ?>

</div><!-- form -->
~~~

そして、`newComment()` メソッドにおいて、AJAX 検証のリクエストに応答するためのコードを追加します。このコードは `ajax` という名前の `POST` 変数があるかどうかチェックします。もしあれば、[CActiveForm::validate] を呼んで検証結果を表示します。

~~~
[php]
protected function newComment($post)
{
	$comment=new Comment;

	if(isset($_POST['ajax']) && $_POST['ajax']==='comment-form')
	{
		echo CActiveForm::validate($comment);
		Yii::app()->end();
	}

	if(isset($_POST['Comment']))
	{
		$comment->attributes=$_POST['Comment'];
		if($post->addComment($comment))
		{
			if($comment->status==Comment::STATUS_PENDING)
				Yii::app()->user->setFlash('commentSubmitted','コメント、有難うございます。コメントは承認後に投稿されます。');
			$this->refresh();
		}
	}
	return $comment;
}
~~~

<div class="revision">$Id$</div>